﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using DiamondDesktop.Model;
using DiamondDesktop.Presenters;
using DiamondDesktop.type;
using DiamondDesktop.Presenters.compare;
using DiamondDesktop.utility;
namespace DiamondDesktop.Model
{
    public class Reminder : DiamondDesktop.Presenters.Observable
    {
        private AbstractTimer timer;    //定时器
        private IDatabase db;         //数据读写接口
        public IMusicPlayer player;    //音乐播放器
        private Properties config;     //配置文件
        private IList<Task> tasks;
        private MsgReporter reporter;

        
        private bool showFinished = false;

        private int checktime;
        private RemindInfo remindInfo;  //提醒的各项设置
        private static RemindInfo defaultRemindInfo;
        private Task taskToRemind = null;
        private Task lastTaskToRemind = null;   //记录上一次到时的任务

        private DeadlineComp deadlineComp = new DeadlineComp();
        private ImportanceComp importanceComp = new ImportanceComp();

        private string datapath;        //任务数据存放地址

        private static Reminder instance = null;  //Reminder的实例

        /**
         *  得到Reminder的唯一实例
         */
        public static Reminder getInstance()
        {
            if (instance == null)
            {
                instance = new Reminder();
            }
            return instance;
        }

        /**
         * 私有构造函数
         */
        private Reminder()
        {
            timer = new SystemTimer();
            player = new WavPlayer();
            reporter = new MsgReporter();
            timer.addObserver(timerHandler);

            this.config = Properties.getInstance();
            try
            {
                datapath = config.getProperty(Config.DATAPATH) + Config.DATA_FILE_NAME;
            }
            catch
            {
                datapath = Config.DATAPATH_VALUE + Config.DATA_FILE_NAME;
            }
            db = new FileDatabase(datapath);

            try
            {
                checktime = Int32.Parse(config.getProperty(Config.SYSTEM_CHECKTIME));
            }
            catch
            {
                checktime = Config.SYSTEM_CHECKTIME_VALUE;
            }
            checkDirExists();
            init();
        }

        /**
         * 初始化
         */
        public void init()
        {
            defaultRemindInfo = makeDefaultRemindInfo();
            loadTaskOfToday();  //载入今日的任务
            setTimer();         //根据任务进行定时  

        }

        public void addReporterObserver(notifyObserver ob)
        {
            reporter.addObserver(ob);
        }

        public void close()
        {
            config.store();
        }

        public void setShowFinished(bool flag)
        {
            showFinished = flag;
        }

        public bool addTask(Task task)
        {
            bool flag = db.saveTask(task);
            if (flag)
            {
                if (task.getTaskStartTime().Date == DateTime.Now.Date)
                {
                    tasks.Add(task);
                }
                notifyObservers(NotifyType.UPDATE);
                setTimer();
            }
            return flag;
        }

        public bool modifyTask(Task task)
        {

            bool flag = db.modifyTask(task);
            if (flag)
            {
                for (int i = 0; i < tasks.Count; i++)
                {
                    if (tasks.ElementAt(i).getTaskId() == task.getTaskId())
                    {
                        tasks.RemoveAt(i);
                        tasks.Insert(i, task);
                    }
                }
                notifyObservers(NotifyType.UPDATE);
                setTimer();
            }
            return flag;
        }

        public bool deleteTask(Task task)
        {
            bool flag = db.deleteTask(task);
            if (flag)
            {
                for (int i = 0; i < tasks.Count; i++)
                {
                    if (tasks.ElementAt(i).getTaskId() == task.getTaskId())
                    {
                        tasks.RemoveAt(i);
                    }
                }
                notifyObservers(NotifyType.UPDATE);
                setTimer();
            }
            return flag;
        }

        public bool remindOnStart()
        {
            if (config.getProperty(Config.REMIND_ON_START) == Config.FALSE)
                return false;
            return true;
        }

        public bool remindOnClosing()
        {
            if (config.getProperty(Config.REMIND_ON_CLOSE) == Config.FALSE)
                return false;
            return true;
        }

        public Summary getSummary()
        {
            Summary s = new Summary();
            s.tasksCount = tasks.Count;
            foreach (Task t in tasks)
            {
                if (t.isMust() && t.getTaskEndTime().Date == DateTime.Now.Date)
                    s.mustFinishCount++;
                if (t.isCompleted())
                {
                    s.finishedCount++;
                    if (t.isMust() && t.getTaskEndTime().Date == DateTime.Now.Date)
                        s.finishedMustCount++;
                }
            }
            return s;
        }

        public IList<Task> getTodayTasks(SortType type)
        {
            List<Task> r = tasks.ToList<Task>();
            if (!showFinished)
            {
                for (int i = 0; i < r.Count; i++)
                {
                    if (r.ElementAt(i).isCompleted())
                    {
                        r.RemoveAt(i);
                        i--;
                    }
                }
            }
            switch (type)
            {
                case SortType.DEADLINE:
                    r.Sort(deadlineComp);
                    break;
                case SortType.IMPORTANCE:
                    r.Sort(importanceComp);
                    break;
                case SortType.PRIORITY:
                    r.Sort(deadlineComp);
                    break;
            }
            return r;
        }

        public IList<Task> getPeriodTasks(DateTime start, DateTime end, SortType type)
        {
            IList<Task> tasks = db.getPeriodTasks(start, end);
            List<Task> r = tasks.ToList<Task>();
            if (!showFinished)
            {
                for (int i = 0; i < r.Count; i++)
                {
                    if (r.ElementAt(i).isCompleted())
                    {
                        r.RemoveAt(i);
                        i--;
                    }
                }
            }
            switch (type)
            {
                case SortType.DEADLINE:
                    r.Sort(deadlineComp);
                    break;
                case SortType.IMPORTANCE:
                    r.Sort(importanceComp);
                    break;
                case SortType.PRIORITY:
                    r.Sort(deadlineComp);
                    break;
            }
            return r;
        }

        public Task getClosestTask()
        {
            return null;
        }

        //当日提醒推迟
        public bool putoffActionTime(int minutes)
        {
            if (tasks != null)
            {
                foreach (Task t in tasks)
                {
                    DateTime tmp = t.getActionEndTime();
                    if (tmp != Utility.DATE_NULL && !t.isCompleted())
                    {
                        if (t.getActionEndTime().AddMinutes(minutes) < t.getTaskEndTime())
                        {
                            t.setActionStartTime(t.getActionStartTime().AddMinutes(minutes));
                            t.setActionEndTime(t.getActionEndTime().AddMinutes(minutes));
                            modifyTask(t);
                        }
                    }
                }
            }
            return true;
        }

        //待删
        private void _notifyObservers() {
            notifyObservers(NotifyType.REMIND);
        }

        //待删 //通知所有的观察者
        private void NotifyObservers() {
            Thread t = new Thread(new ThreadStart(_notifyObservers));
            t.Start();
        }

        /**
        * 检查存放任务数据的文件夹是否存在，如果不存在则创建文件夹
        */
        private void checkDirExists()
        {
            if (!Directory.Exists(datapath))
                Directory.CreateDirectory(datapath);
        }

        /**
         * 载入今天需要完成的任务。
         */
        private void loadTaskOfToday()
        {
            string lastUseTime = config.getProperty(Config.LAST_USE_TIME);  //得到上次使用软件的时间
            DateTime current = DateTime.Now;
            DateTime last = new DateTime();
            if (lastUseTime != null)
                last = DateTime.Parse(lastUseTime);

            if (lastUseTime == null || current.Date == last.Date)
            {
                tasks = db.getDaySchedule(current);
            }
            else
            {
                tasks = db.getTodaySchedule(last, current);
                db.storeTasks(tasks, current);
            }
            config.setProperty(Config.LAST_USE_TIME, current);  //记录此次使用的时间
        }

        private RemindInfo makeDefaultRemindInfo()
        {
            return new RemindInfo(config.getProperty(Config.SOUND_PATH) + config.getProperty(Config.DEFAULT_SOUND));
        }
        private void timerHandler(Object obj)
        {

                timer.stop();   
                if (taskToRemind != null)
                {
                    try
                    {
                        player.setFile(remindInfo.getMusicPath());
                        player.play();
                    }
                    catch
                    {

                        reporter.reporMessage("载入音乐文件出错或音乐文件不存在");
                    }
                    lastTaskToRemind = taskToRemind;
                    notifyObservers(NotifyType.REMIND);
                }
                else
                {


                }
                setTimer();   //重新设置定时器
        }

        public Task getTaskToRemind()
        {
            return lastTaskToRemind;
        }

        /**
         *重新设置定时器 
         */
        private void setTimer()
        {
            DateTime tmp = DateTime.Now.AddMinutes(checktime);
            DateTime cur = DateTime.Now;
            taskToRemind = null;
            remindInfo = defaultRemindInfo;
            if (tasks != null)
            {
                foreach (Task t in tasks)
                {
                    if (!t.isCompleted()) {
                        DateTime d = t.getActionStartTime();
                        if (d != Utility.DATE_NULL && d > cur && t.getActionStartTime() < tmp)
                        {
                            tmp = t.getActionStartTime();
                            taskToRemind = t;
                            if (t.getRemindInfo() != null)
                                remindInfo = t.getRemindInfo();
                        }
                        d = t.getTaskEndTime();
                        if (d > cur && d < tmp)
                        {
                            tmp = t.getTaskEndTime();
                            taskToRemind = t;
                        }              
                    }
                }
            }
            long sub = tmp.Ticks - DateTime.Now.Ticks;
            timer.setInterval((long)Math.Ceiling((double)sub / 10000000));
            timer.start();
            
        }

    }
}
